#!/usr/bin/env python
"""reddList -- make a lists of links
Order by popularity according to technorati, yahoo, google data.  Cache and call it points.
Currently only uses Yahoo"""
__revision__ = "9"
__license__ = "MIT License"
__author__ = "Keizo Gates <kzo@kzo.net>"

#technorati api key for keizogates c7ce030dea670d7a7ecbe30fd11090fd

import os
import web
import sha
from flup.middleware.session import DiskSessionStore, SessionMiddleware

import urllib
from xml.sax.handler import ContentHandler
from xml.sax import parse

import db_params

urls = (
    '/', 'index',
    '/login','login',
    '/logout','logout',
    '/admin','admin',
    '/addlink','addlink',
    '/addlist','addlist',
    '/delete','delete',
    '/update','update',
    '/vote','vote',
    '/yahoo','yahoo',
)

#
## AUTHORIZATION STUFF
#
def dologin(user):
    session = web.ctx.environ['com.saddi.service.session'].session
    session['id'] = user.id
    session['username'] = user.username
    session['groups'] = user.groups
    session['loggedin'] = 1
    
def dologout():
    session = web.ctx.environ['com.saddi.service.session'].session
    session.invalidate()

def initsession(session):
    session['id'] = 0
    session['username'] = ''
    session['groups'] = ''
    session['loggedin'] = 0

def checkauth(session):
    if session['loggedin'] == 1:
        return True
    return False

def checkaccess(auth=False, access=''):
    def decorator(func): 
        def proxyfunc(self, *args, **kw):
            service = web.ctx.environ['com.saddi.service.session']
            session = service.session
            if service.isSessionNew:
                initsession(session)
            if auth == True:
                if not checkauth(session):
                    return web.redirect('login')
            if access != '':
                groups = session['groups'].split(',')
                if access not in groups: 
                    return web.redirect('login')
            return func(self, *args, **kw)
        return proxyfunc
    return decorator


#
## pages
#

class index:
    def GET(self):
        reddLists = web.query("SELECT * FROM rl_links ln LEFT JOIN rl_lists ls ON \
            ln.list = ls.id ORDER BY ls.rank, ls.heading, ln.points DESC")
        web.render('index.html')

class login:
    @checkaccess()
    def GET(self):
        errors=''
        web.render('login.html')

    @checkaccess()
    def POST(self):
        #user = web.storify({
         #   'id':1,
          #  'username':'admin',
           # 'password':'admin',
            #'groups':'admin'
        #})
        inp = web.input()
        m = sha.new(inp.password)
        inp.password = m.hexdigest()
        #query = web.query("select * from rl_users where username='%s'" % inp.username)
        query = web.select('rl_users',where="username=$inp.username", vars=locals())
        if query: 
            user = query[0]
            if inp.username == user.username and inp.password == user.password:
                dologin(user)
                web.redirect('admin')
            else:
                errors='wrong password'
                web.render('login.html')
        else:
            errors='invalid username'
            web.render('login.html')


class logout:
    @checkaccess()
    def GET(self):
        dologout()
        web.redirect('/')

class admin:
    @checkaccess(auth=True, access='admin')
    def GET(self):
        reddLists = web.query("SELECT *, ln.id lid FROM rl_links ln LEFT JOIN rl_lists ls ON \
            ln.list = ls.id ORDER BY ls.rank, ls.heading, ln.points DESC")
        lists = web.select('rl_lists')
        web.render('admin.html')

class addlink:
    @checkaccess(auth=True, access='admin')
    def POST(self):
        i = web.input()
        i.points = inlinkData('rl_links',i.link,results=1)
        web.insert('rl_links',list=i.list,points=i.points,title=i.title,link=i.link,info=i.info)
        web.redirect('admin')

class addlist:
    @checkaccess(auth=True, access='admin')
    def POST(self):
        i = web.input()
        web.insert('rl_lists',heading=i.heading)
        web.redirect('admin')

class delete:
    @checkaccess(auth=True, access='admin')
    def POST(self):
        #web.delete('links',int())
        web.redirect('admin')

class update:
    @checkaccess(auth=True, access='admin')
    def POST(self):
        i = web.input()
        web.update('rl_links',int(i.lid),link=i.link,title=i.title,info=i.info)
        if i.ajax:
            print '<li id="',i.lid,'">'
            print '<span id="title',i.lid,'">',i.title,'</span> <span class="points">(<span id="link',i.lid,'">',i.link,'</span>) </span> - <span id="info',i.lid,'">',i.info,'</span>'
            print '</li>'
        else:
            web.redirect('admin')
        
class vote:
    @checkaccess(auth=True, access='admin')
    def POST(self):
        i = web.input()
        web.update('rl_lists',int(i.id),rank=int(i.rank))
        #web.query('update lists set rank=rank+$vote where id=$id',vars=i)
        web.redirect('admin')

class yahoo:
    @checkaccess(auth=True, access='admin')
    def GET(self):
        myData = web.select('rl_links')
        for entry in myData:
            print entry.title
            print entry.link
            entry.points = inlinkData('reddList',entry.link,results=1)
            print entry.points
            web.update('rl_links',int(entry.id),points=entry.points)

#
##begin yahoo stuff
#
URI = "http://api.search.yahoo.com/SiteExplorerService/V1/inlinkData"
def inlinkData(appid, # see http://developer.yahoo.net/faq/index.html#appid
                query, #  The domain or path to get inlink data for.
                results=50, # The number of results to return.
                start=1, #  The starting result position to return (1-based).
                        # The finishing position (start + results - 1) cannot
                        # exceed 1000.
                entire_site=None # Specifies whether to provide results for the
                                # entire site, or just the page referenced by
                                # the query. If the query is not a domain URL
                                # (i.e. it contains path information, such as
                                # http://smallbusiness.yahoo.com/webhosting/),
                                # this parameter has no effect.
            ):
    d = dict(appid=appid,
        query=unicodify(query).encode('utf-8'),
        results=int(results),
        start=int(start)
        )
    if entire_site:
        # xxx perhaps this parameter should be automatically
        # set based on the 'query' having a path
        d['entire_site'] = 1
    
    u = URI+'?'+urllib.urlencode(d)
    f = urllib.urlopen(u)
    inlink = inlinkDataYahooHandler()
    parse(f,inlink)
    try:
        return inlink.total
    except:
        return 0

def unicodify(x):
    if isinstance(x, unicode):
        return x
    try:
        return x.decode()
    except UnicodeDecodeError:
        try:
            return x.decode('utf-8')
        except UnicodeDecodeError:
            return x.decode('latin-1')

class inlinkDataYahooHandler(ContentHandler):
    def startElement(self, name, attrs):
        if name == 'ResultSet':
            self.total = attrs['totalResultsAvailable']

#
## MIDDLEWARE FACTORIES
#
def session_mw(app):
    sessionStore = DiskSessionStore(storeDir="%s/sessions/" % os.getcwd(), timeout=5)
    return SessionMiddleware(sessionStore, app) 


#web.webapi.internalerror = web.debugerror
if __name__ == "__main__": 
    web.config.db_parameters = dict(dbn='mysql', user=db_params.user, pw=db_params.password, db=db_params.database)
    
    #production:
    web.run(urls, globals(), *[session_mw])
    
    #development laptop:
    #web.internalerror = web.debugerror
    #web.run(urls, globals(), *[web.reloader, session_mw])
